package widgets;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

/**
 * This class is a replacement for {@link JDialog}.
 *
 * @author Neil Dickson
 */
public class CustomDialog extends JPanel implements KeyListener {
	private final	Container	rootParent;
	private			CustomPopup	popup;
	protected final	boolean		isModal;
	protected		boolean		isVisible;
	protected		Point		location;

	private			Timer		backgroundTimer;

	public final int		horizontalSpace;
	public final int		verticalSpace;
	public final int		radius;
	public final int		shadowSpacing;

	public static final Font	FONT				=	new Font("Arial",Font.PLAIN,14);
	public static final int		LINE_HEIGHT			=	(int) (FONT.getSize()*1.3);
	public static final Font	HEADER_FONT			=	new Font("Arial",Font.BOLD,16);

	public static final Color	TRANSPARENT			=	new Color(0,true);
	public static final Color	ALMOST_TRANSPARENT	=	new Color(0x00FFFFFF,true);
	public static final Color	BACKGROUND_COLOUR	=	Color.WHITE;
	public static final Color	FONT_COLOUR			=	Color.BLACK;
	public static final Color	LINE_COLOUR			=	new Color(0xC0C0C0);
	public static final int		SHADOW_OPACITY		=	0xC0;

	public CustomDialog(Container rootParent) {
		this(rootParent,true);
	}
	public CustomDialog(Container rootParent,boolean modal) {
		this(rootParent,modal,20,12,32,8);
	}
	public CustomDialog(Container rootParent,boolean modal,int horizontalSpace,int verticalSpace,int radius,int shadowSpacing) {
		super(null);
		this.rootParent = rootParent;
		setBackground(TRANSPARENT);
		setOpaque(false);
		isModal = modal;
		isVisible = false;
		this.horizontalSpace = horizontalSpace;
		this.verticalSpace = verticalSpace;
		this.radius = radius;
		this.shadowSpacing = shadowSpacing;
	}

	public boolean isVisible() {
		return isVisible;
	}
	public void setVisible(boolean b) {
		if (b) {
			if (isVisible) {
				setVisible(false);
			}
			if (isModal) {
				final JPanel blockingPanel = new JPanel(null) {
					protected void paintComponent(Graphics g) {
						g.setColor(getBackground());
						g.fillRect(0,0,getWidth(),getHeight());
					}
				};
				blockingPanel.setBackground(ALMOST_TRANSPARENT);
				blockingPanel.setOpaque(false);
				addFocusListener(new FocusListener() {
					public void focusGained(FocusEvent e) {}
					public void focusLost(FocusEvent e) {
						CustomDialog.this.requestFocus();
					}
				});
				requestFocus();
				blockingPanel.setBounds(0,0,rootParent.getWidth(),rootParent.getHeight());
				setLocation((this.location!=null) ? this.location : new Point((rootParent.getWidth()-getWidth())>>>1,(rootParent.getHeight()-getHeight())>>>1));
				blockingPanel.add(this);
				Point location = new Point(0,0);
				SwingUtilities.convertPointToScreen(location,rootParent);
				popup = new CustomPopup(rootParent,blockingPanel,location);
				popup.show();
				if (rootParent instanceof ModalParent) {
					((ModalParent)rootParent).setModalDialog(this);
				}
				isVisible = true;
				backgroundTimer = new Timer(100,new ActionListener() {
					public void actionPerformed(ActionEvent e) {
						Color c = blockingPanel.getBackground();
						if (c.getAlpha()<0x60) {
							c = new Color(c.getRGB()+0x18000000,true);
							blockingPanel.setBackground(c);
							blockingPanel.repaint();
						}
						else {
							Timer timer = backgroundTimer;
							if (timer!=null) {
								timer.stop();
								backgroundTimer = null;
							}
						}
					}
				});
				backgroundTimer.start();
			}
			else {
				if (location==null) {
					location = new Point((rootParent.getWidth()-getWidth())>>>1,(rootParent.getHeight()-getHeight())>>>1);
					SwingUtilities.convertPointToScreen(location, rootParent);
				}
				popup = new CustomPopup(rootParent,this,location);
				popup.show();
				isVisible = true;
			}
		}
		else if (isVisible) {
			popup.hide();
			if (isModal && (rootParent instanceof ModalParent)) {
				((ModalParent)rootParent).setModalDialog(null);
			}
			Timer timer = backgroundTimer;
			if (timer!=null) {
				timer.stop();
				backgroundTimer = null;
			}
			isVisible = false;
		}
	}

	public void setPopupLocation(Point p) {
		location = p;
		// Reposition the popup if already visible by setting it visible again
		if (isVisible) {
			setVisible(true);
		}
	}
	public void setPopupLocation(int x, int y) {
		setPopupLocation(new Point(x,y));
	}
	public void updatePopupLocationMiddle() {
		setLocation(new Point((rootParent.getWidth()-getWidth())>>1,(rootParent.getHeight()-getHeight())>>1));
	}

	protected void paintComponent(Graphics g) {
		Graphics2D g2 = (Graphics2D)g;
		g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
		for (int i=1;i<= shadowSpacing;++i) {
			int transparency = SHADOW_OPACITY/ shadowSpacing;
			g2.setColor(new Color(0,0,0,transparency));
			g2.fillRoundRect(shadowSpacing +i-1, shadowSpacing +i-1,getWidth()- shadowSpacing -i*2+2,getHeight()- shadowSpacing -i*2+2, radius + radius -i+1, radius + radius -i+1);
		}

		g2.setColor(BACKGROUND_COLOUR);
		g2.fillRoundRect(0,0,getWidth()- shadowSpacing,getHeight()- shadowSpacing, radius + radius, radius + radius);
		g2.setColor(LINE_COLOUR);
		g2.drawRoundRect(0,0,getWidth()- shadowSpacing,getHeight()- shadowSpacing, radius + radius, radius + radius);

		g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
	}

	public boolean interceptsKeyEvents() {
		return true;	// Intercept KeyEvents, but possibly different in subclasses.
	}
	public void keyTyped(KeyEvent e) {
		// Do nothing in this method.
	}

	public void keyPressed(KeyEvent e) {
		// Do nothing in this method, but possibly something in subclasses.
	}

	public void keyReleased(KeyEvent e) {
		// Do nothing in this method, but possible something in subclasses.
	}

	public static interface ModalParent {
		void setModalDialog(CustomDialog dialog);
	}
}
